home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / paper / extendedAbstract < prev    next >
Encoding:
Text File  |  1992-12-01  |  24.1 KB  |  487 lines

  1.                 Sprite on Mach
  2.  
  3.                  Mike Kupfer
  4.           University of California, Berkeley
  5.  
  6. Abstract
  7.  
  8. Sprite is a distributed operating system that supports a fast
  9. single-image network file system and transparent process migration.
  10. Over a period of 19 months I ported Sprite to run as a server on top
  11. of the Mach 3.0 microkernel.  Although the resulting server does not
  12. implement some Sprite features, it can run in an existing Sprite
  13. cluster, and it supports standard UNIX programs like vi, gcc, and
  14. make.
  15.  
  16. Porting Sprite to Mach was generally straightforward, though there
  17. were some difficulties.  Many of the problems were related to
  18. asynchronous interactions between the Sprite server, Mach, and Sprite
  19. user processes.  Others resulted from trying to maintain native
  20. Sprite's internal interfaces in the Sprite server.
  21.  
  22. Although machine-dependent code accounts for 14% of the source lines
  23. in the Sprite kernel, it accounts for only 1% of the source lines in
  24. the Sprite server.  I believe that this will significantly simplify
  25. porting Sprite to new hardware platforms.  Unfortunately, the Sprite
  26. server runs the Andrew benchmark at only 38% of the speed of native
  27. Sprite.  None of the performance problems appear insurmountable, but
  28. they could require a long time to track down and fix.
  29.  
  30.  
  31. 1. Introduction
  32.  
  33. Sprite is a distributed operating system that was developed at the
  34. University of California, Berkeley [1].  It features a fast
  35. single-image network file system [2], transparent process migration
  36. [3], and a high-performance log-structured local filesystem [4].
  37. Sprite was originally written to support the SPUR multiprocessor
  38. project at Berkeley [5], so the kernel is multi-threaded and uses
  39. fine-grain locking.
  40.  
  41. I have ported the Sprite kernel to run as a server on top of Mach
  42. 3.0.  The server does not have complete Sprite functionality, but it
  43. can run most UNIX commands as a client of native Sprite file servers.
  44. I used the modified Andrew benchmark [8] to partially tune the server
  45. and to analyze the remaining performance problems.
  46.  
  47. In the following sections I will explain why I ported Sprite to Mach;
  48. I will sketch the design of the Sprite server, with particular
  49. attention to some of the problem areas; I will discuss the relative
  50. sizes and portability of native Sprite and the Sprite server; I will
  51. analyze the performance of the Sprite server; I will evaluate the
  52. success of the Sprite server; and I will present some conclusions that
  53. I have drawn.
  54.  
  55.  
  56. 2. Why mix Sprite and Mach?
  57.  
  58. The Sprite project became interested in Mach for three reasons: to
  59. make Sprite more portable, to make Sprite easier to distribute to
  60. external sites, and to verify whether Mach is a suitable platform for
  61. building distributed systems.
  62. % Sprite currently
  63. % runs on the DECStation 5000 and on Sun SPARC systems.  In the past it
  64. % has also run on the DECStation 3100, the Sun 2, the Sun 3, prototype
  65. % SPUR systems, and the Sequent Symmetry.  Most of these ports were
  66. % performed by students in the Sprite group.  These ports were
  67. % time-consuming and delayed progress on the students' research work.
  68. % It was hoped that by putting Sprite on top of Mach, the Sprite group
  69. % could leave the hardware ports to the Mach community, freeing the
  70. % Sprite group to concentrate on more interesting research projects.
  71.  
  72. (The full paper will elaborate on these reasons.  The portability and
  73. software distribution issues are a result of the small size of the
  74. Sprite group.  The discussion about Mach being a suitable platform
  75. will mention the UX server and the shared memory server as being the
  76. only relevant prior art for a highly-networked system like Sprite.  I
  77. will claim that Sprite stresses Mach more than either of these
  78. servers, and we in the Sprite group were concerned about possible
  79. performance problems in the network code.)
  80.  
  81. These project goals led to the following design goals.  First, the
  82. revised Sprite system should be highly portable.  This led to
  83. implementing Sprite as a server, under the assumption that
  84. machine-dependent code such as device drivers and memory management
  85. would be written by the Mach community, not the Sprite group.  A
  86. second goal was simplicity, so as not to complicate future Sprite
  87. research work.  A third goal was to minimize changes to existing
  88. Sprite code.  The point of this goal was to minimize development time
  89. and to simplify synchronizing native Sprite code changes with the
  90. Sprite server.  It led to a single-server, rather than a multi-server,
  91. approach.  The fourth goal was to get performance comparable to native
  92. Sprite.  Slight performance degradation was considered acceptable
  93. in return for improved portability.
  94.  
  95.  
  96. 3. Design of the Sprite server
  97.  
  98. As a first approximation, Mach can be thought of as a high-level
  99. abstract machine.  It provides processes, scheduling, a simple
  100. interface for accessing a process's memory, and a machine-independent
  101. interface for accessing local devices such as disks or networks.  The
  102. C Threads library provides threads, locks, and condition variables.
  103. Thus the first step in porting Sprite was to rip out all the low-level
  104. native code whose functionality was already provided by Mach,
  105. replacing it with a facade that maintains Sprite's internal
  106. interfaces.  This process is similar to the transformation that was
  107. used to implement the ``UX'' UNIX server [6, 7].
  108.  
  109. On the user side, emulation code was added to the C runtime library.
  110. This code translates Sprite system calls into Matchmaker RPC requests
  111. to the Sprite server.  Again, this setup is similar to the one used in
  112. the UNIX server.
  113.  
  114. One important difference between the UNIX and Sprite servers is how
  115. they use external pagers.  The UNIX server provides an external pager
  116. for mapped files, including program text, but it uses the Mach default
  117. pager for swap storage (i.e., a process's heap and stack).  The Sprite
  118. server provides an external pager that backs the entire address space
  119. of a user process, including its heap and stack.  This design lets a
  120. process page from a network file server, as is done in native Sprite.
  121. Sprite uses this feature to support diskless operation - almost all
  122. Sprite workstations are diskless - and to support process migration.
  123.  
  124. Most of the changes to port Sprite to Mach were straightforward.
  125. Nonetheless, some changes presented unexpected difficulties.  Many of
  126. the problems were related in some way to asynchronous interactions
  127. between the Sprite server, Sprite user processes, and Mach.  For
  128. example, some data structures, such as memory objects and process
  129. table entries, are logically shared between the Sprite server and
  130. Mach, and special care is needed to ensure that the data structures
  131. are not freed prematurely or leaked.  (The full paper will elaborate
  132. on one or both of these examples, depending on space availability,
  133. with pictures.  If there is space, it will also discuss a race in the
  134. implementation of sbrk() and complications to handling copyin errors.)
  135. No single problem was insurmountable, but each required extra time to
  136. get the details of the design and implementation correct.
  137.  
  138. % For example, consider what happens when a process maps a file and then
  139. % exits.  The Sprite server cannot free its internal representation of
  140. % the mapped file until it receives a memory_object_terminate
  141. % notification from the Mach kernel.  Now consider what happens if a new
  142. % user process tries to map the same file before the previous mapping
  143. % has been cleaned up.  Should the server create a new object to
  144. % represent the mapping?  Should it wait for the old one to be
  145. % destroyed?
  146.  
  147. A similar problem was how to invoke a user signal handler for signals
  148. that are generated asynchronously.  (The full paper will explain this
  149. in more detail.  The current implementation does not support
  150. asynchronous signal delivery when there is a user handler for the
  151. signal.  Instead the server passes back a ``pending signal'' flag for
  152. almost all requests.  If this flag is set, the emulation library gets
  153. the signal information and invokes the handler.)
  154.  
  155. % In native Sprite the kernel can
  156. % simply wait until the user process returns from a time slice interrupt
  157. % or system call.  Strictly speaking, this is not an option for the
  158. % Sprite server because the process could be in an infinite loop waiting
  159. % for a signal.  Instead the server can freeze the process, change its
  160. % registers and stack to invoke the signal handler, and resume the
  161. % process.  Unfortunately, if the user process is making a Mach system
  162. % call, signal delivery should be delayed until the system call is
  163. % complete.  Because of the potential complexity and performance
  164. % problems associated with a general solution (e.g., looking at the
  165. % process's program counter), we decided not to attempt asynchronous
  166. % signal delivery when there is a signal handler.  Instead Sprite calls
  167. % return a flag to the emulation library saying that there is a pending
  168. % signal, and the emulation library makes a special call to invoke the
  169. % signal handler.  We expect this design to be acceptable in practice.
  170.  
  171. Maintaining Sprite's internal process interface was also complicated
  172. in places.  Native Sprite is like UNIX in that user processes run in
  173. ``kernel mode'' after an interrupt or after executing a trap.  As a
  174. consequence, native Sprite was designed so that a process can kill or
  175. suspend only itself.  An attempt to kill or suspend a different
  176. process is simply a request, which the target process eventually acts
  177. on.  In contrast, the Sprite server is a separate Mach task that user
  178. processes invoke via RPCs.  The server can simulate the effects of
  179. traps and interrupts through an internal pool of threads, but there
  180. are some problems with this approach.  First, special care is needed,
  181. e.g., in exit() and exec(), to ensure that the threads correctly
  182. manage internal resources like buffers.  Second, because the Sprite
  183. server does not handle time slice interrupts, it cannot guarantee that
  184. user processes will notice attempts to kill or suspend them.  Thus,
  185. unlike in native Sprite, user processes must be able to kill or
  186. suspend other user processes.  This requirement led to many changes in
  187. the locking strategy employed by the process management and signals
  188. code in Sprite, and these changes were the source of many bugs.
  189. % Deadlocks in the exit() code were common during development and
  190. % testing.
  191. % Special code to handle suspension is needed in the system request
  192. % code, in case a process is suspended after it has submitted a
  193. % request but before the request has been acted on.  Also, native
  194. % Sprite integrates suspension with the sched/sync code; the server
  195. % requires that ugly wait loop.
  196.  
  197.  
  198. 4. Status and code measurements
  199.  
  200. This section explains the current status of the Sprite server and
  201. presents some code size measurements.
  202.  
  203. I developed the Sprite server over a period of 19 months.  The first 7
  204. months of the project were a half-time effort; the remaining 12 months
  205. were full-time, including 2.5 months of performance tuning.  I began
  206. development on a Sun 3 but later moved to a DECStation 5000.
  207.  
  208. % Moved to ds5000 for performance reasons and to avoid having to deal
  209. % with signals support for 2 architectures.
  210.  
  211. The Sprite server supports standard UNIX programs like vi, gcc, and
  212. make.  Nonetheless, the implementation is still a prototype, and it
  213. lacks some important features.  The server design includes support for
  214. these features; I simply lacked the time to implement them.  The
  215. missing features include
  216.  
  217. - binary compatibility (with both the vendor operating system and
  218.   native Sprite) 
  219. - local disk access
  220. - support for debugging user processes
  221. - process migration
  222.  
  223. A Sprite DECStation kernel with the same functionality as the Sprite
  224. server contains roughly 143,000 lines of code, of which 27,000 lines
  225. are machine-dependent, including 3600 lines of assembly code.  The
  226. Sprite server contains 111,000 lines of code, of which 1300 lines are
  227. machine-dependent.  The server contains 4 lines of assembly code to
  228. help debug locking errors.
  229.  
  230. In going from native Sprite to the Sprite server, I preserved about
  231. 90,000 lines of code (63%).  I threw away another 39,000 lines of
  232. code (27%), and I rewrote the remaining code, about 14,000 lines
  233. (10%), for use with Mach.  The thrown away code consisted of low-level
  234. (and often machine-dependent) code for device, process, and memory
  235. management, plus code that duplicated Mach functionality (e.g., the
  236. process scheduler and a kernel debugger).  Most of the rewritten code
  237. was for process and memory management, ``system call'' support, and
  238. Sprite's internal lock package.
  239.  
  240. To support the missing functionality mentioned earlier in this
  241. section, I would have to port an additional 58,000 lines of code, of
  242. which 2400 lines are machine-dependent.  I expect that about 52,000
  243. lines of this code would not require change, another 2000 lines would
  244. get thrown away, and the remaining 4000 lines would get rewritten.
  245.  
  246. (The full paper will use bar charts to present some or all of these
  247. numbers.)
  248.  
  249.  
  250. 5. Performance
  251.  
  252. Due to time constraints, I used only one benchmark to tune the Sprite
  253. server: the modified Andrew benchmark [8].  This benchmark copies a
  254. file tree, scans the tree several times, and then compiles some window
  255. system code.  Unless otherwise noted, all the performance numbers in
  256. this section were obtained on a DECStation 5000 with at least 32
  257. megabytes of memory, using files stored on a native Sprite file
  258. server.
  259.  
  260. As (will be) shown in the table, native Sprite runs the benchmark in
  261. 91 seconds.  The UNIX server (UX34) and Ultrix 4.2, using only
  262. local files, need around 118 seconds.  The time for Ultrix 4.2 goes up
  263. to 141 seconds when the files are on a Prestoserve-equipped NFS
  264. server.  The Sprite server's fastest time for the benchmark is 237
  265. seconds.
  266.  
  267. Early versions of the Sprite server required around 440 seconds to run
  268. the benchmark.  Most of the performance fixes to reach the current
  269. time were in three areas: caching of text segments, reduced Sprite RPC
  270. latency, and more efficient string management in exec().  (The full
  271. paper will explain these in more detail and tell how much they
  272. contributed to the overall improvement.)
  273.  
  274. I have analyzed the 146 second gap between native Sprite and the
  275. Sprite server, and I can explain about 98 seconds of it.  I know
  276. more or less where the remaining 48 seconds are being spent, but not
  277. why.  Tuning stopped when I changed employers in July 1992.
  278.  
  279. The paper will explain the current top 5 understood or partially
  280. understood bottlenecks.  They are
  281.  
  282. (1) overhead in fork() from copying the heap and stack, which accounts
  283. for 45 seconds.  This problem is present because Mach does not
  284. currently support copy-on-write for externally managed memory objects.
  285.  
  286. (2) copyin/copyout delays for read() and write(), which account for 18
  287. seconds.  The UNIX server uses mapped files to avoid this problem.  A
  288. similar approach for Sprite is not straightforward, because Sprite
  289. doesn't support consistent access to mapped files that are shared by
  290. multiple clients.
  291.  
  292. (3) higher Sprite RPC latency (despite the improvements made during
  293. tuning), which accounts for 11 seconds.  I suspect that most of the
  294. time is spent in the Mach networking code, though I was unable to
  295. verify this for the network input path.
  296.  
  297. (4) overhead after exec() from faulting in heap and stack pages, which
  298. accounts for 8 seconds.  The Sprite server currently creates new heap
  299. and stack segments in exec(); I expect that a better approach is to
  300. zero out and reuse the old segments.
  301.  
  302. (5) unexplained Sprite ``system call'' time, which accounts for 8
  303. seconds.  I suspect that this problem results from unnecessary
  304. context switching, and that it can be fixed by changing how the Sprite
  305. server garbage collects process table entries.
  306.  
  307. % Put a summary (a short, coherent summary) of the 5 items here?
  308.  
  309. % Of the understood bottlenecks, the largest is in fork().  Although the
  310. % Mach external pager interface supports copy-on-write copying of memory
  311. % objects, the implementation is broken, so the benchmark spends 45
  312. % seconds just copying heap and stack pages.  The UNIX server avoids
  313. % this problem by using the default pager for user heaps and stacks, but
  314. % as explained earlier, this is not an option for Sprite.  Fortunately,
  315. % there are plans to fix copy-on-write for externally managed memory
  316. % objects [JSB private comm.].
  317. % The next largest bottleneck (18 seconds) is spent copying bytes to and
  318. % from user space, mostly for read() and write().  Our measurements
  319. % indicate that the real culprit is the cost of the cross-address-space
  320. % memory operations, rather than the bcopy cost just to move the bytes.
  321. % The UNIX server uses mapped files to avoid this bottleneck [ref UX
  322. % paper and Dean/Armand paper].
  323. % Unfortunately, mapped files in Sprite do not enjoy the same network
  324. % consistency guarantees that files accessed through a read/write
  325. % interface enjoy.  This is not an inherent flaw in Sprite's design, but
  326. % fixing it would require changes to native Sprite as well as to the
  327. % Sprite server.  It may be worth exploring other alternatives (e.g.,
  328. % having the server cache mappings into user processes) before resorting
  329. % to mapped files.
  330. % Another large slowdown in the system is caused by an increase in RPC
  331. % latency.  Native Sprite can do a null RPC between two DECstation 5000s
  332. % in 0.85 milliseconds.  The null RPC time between the Sprite server and
  333. % a native Sprite system is 2.2 milliseconds.  For the Andrew benchmark,
  334. % which causes about 8200 Sprite RPCs, this translates to a
  335. % slowdown of about 11 seconds.  It's not clear what the right solution
  336. % is for this problem.  (Adopt NORMA RPC?  (See 1992 Mach Usenix paper;
  337. % is it applicable?)  Replace the packet filter architecture with the
  338. % OSF proposal?  Use the X-kernel?)
  339. % Another slowdown is caused by unnecessary faults during exec().  The
  340. % Sprite server currently destroys and recreates the heap and stack
  341. % segments during exec().  The Andrew benchmark causes about
  342. % 8300 heap and stack faults; at 1 millisecond per fault (where does
  343. % this number come from??), this causes a delay of about 8 seconds.  To
  344. % fix this problem, the Sprite server can reuse heap and stack segments.
  345. % Unfortunately, it will return once the Sprite server starts using
  346. % copy-on-write for fork().
  347. % Another large bottleneck is in the code that processes Sprite "system
  348. % calls" (really MIG calls) from Sprite user processes.  After comparing
  349. % the UNIX server "system call" times with the Sprite server times, we
  350. % estimate that this bottleneck is adding 8 seconds to the Andrew
  351. % benchmark time.  We think that this is due to excessive context
  352. % switches in that part of the Sprite server, but this hypothesis has
  353. % not yet been verified.
  354.  
  355.  
  356. 6. Evaluation
  357.  
  358. This section will evaluate the Sprite server according to the design
  359. goals presented earlier in the paper: portability, simplicity,
  360. minimizing changes to native Sprite, and performance.
  361.  
  362. The Sprite server appears to be highly portable.  It contains less
  363. code than an equivalent Sprite kernel, plus there is very little
  364. machine-dependent code and essentially no assembly code.  The
  365. unimplemented code from native Sprite is mostly machine-independent,
  366. so a fully functional Sprite server should still be very portable.
  367.  
  368. Although the Sprite server is not as simple as I'd like (because of
  369. the design complications described in section 3), most of the Sprite
  370. server design and implementation were straightforward, and debugging
  371. the server with gdb was generally easy.  In fact, I was able to
  372. track down some bugs from native Sprite that had long been puzzling
  373. the Sprite group.
  374.  
  375. Porting Sprite to Mach involved an acceptably small number of changes
  376. to native Sprite.  Most of the server code is identical to the kernel
  377. code from which it is derived, and I made few changes to Sprite's
  378. internal interfaces.  Furthermore, the Sprite server runs in an
  379. existing Sprite cluster.  No changes - other than adding a new machine
  380. type - were made to the native Sprite systems to accommodate the
  381. Sprite server.
  382.  
  383. Unfortunately, I was not able to meet my performance goal.  Assuming
  384. that I can apply the fixes that I know of or expect to see soon, I am
  385. still left with a performance of about 165 seconds for the Andrew
  386. benchmark, which is still worse than Ultrix using NFS.  I believe that
  387. additional tuning could reduce the benchmark time even further, though
  388. this would probably be a time-consuming task.
  389.  
  390.  
  391. 7. Future work
  392.  
  393. As mentioned earlier in the paper, I am no longer employed by the
  394. University of California, and it is unlikely that anyone will do
  395. additional work on the Sprite server.  If development were to
  396. continue, the obvious first task would be to continue performance
  397. tuning.  More work is needed to make the Sprite server perform
  398. adequately on the Andrew benchmark, and there are other benchmarks
  399. that the server should be tested on.  Furthermore, a
  400. production-quality Sprite server would require the remaining
  401. functionality mentioned in section 4.  
  402. % mention the WPI synthetic benchmarks [ref]?  It would be nice 
  403. % if you could find a different reference?  (Reread the Mach workshop 
  404. % paper; maybe it's better than you remember.)
  405.  
  406. In addition to mundane development work, it would be useful to conduct
  407. additional research using the Sprite server.  For example, it would be
  408. interesting to compare the performance of the Sprite server with the
  409. performance of a similar server that uses Mach IPC for access to
  410. remote devices or process migration.
  411. % Look at the FS/VM cache boundary stuff?
  412.  
  413.  
  414. 8. Conclusions
  415.  
  416. Porting Sprite to Mach was a mixed success.  On the one hand, it
  417. greatly reduced the amount of machine-dependent code in Sprite, which
  418. should make Sprite much easier to port to new hardware.  The
  419. asynchronous interfaces provided by Mach require some unpleasant
  420. complexity in the Sprite server, but this complexity is manageable.
  421. On the other hand, the server is almost unusably slow, and it appears
  422. that much work is still needed to bring performance within striking
  423. distance of the native system.
  424.  
  425. At least one third of the performance gap results from the distributed
  426. nature of Sprite.  However, the slowdown is not primarily due to RPC
  427. latency or throughput problems.  Rather, it is due to the Sprite
  428. server's heavy use of an external pager, plus problems such as its
  429. inability to use mapped files to avoid copy overhead.  The lesson here
  430. seems to be that there is more to high-performance distributed systems
  431. than fast communication, and Mach 3.0 currently does not support some
  432. designs as well as others.  For some problems (e.g., copy-on-write for
  433. external pagers) it should be possible to fix Mach, but in other cases
  434. (e.g., use of mapped files for performance), it may be necessary to
  435. redesign the server instead.
  436.  
  437. Thus, if I ask whether it is worth porting an existing operating
  438. system to run on top of Mach, the answer is ``maybe.''  For a research
  439. system like Sprite, with its small development community, increased
  440. portability seems attractive enough to warrant a large one-time
  441. porting and tuning effort.  For commercial systems, though, a more
  442. portable server seems less alluring, particularly if the vendor has to
  443. port Mach as well.  I think that commercial vendors will have to
  444. consider the potential benefits of Mach other than portability before
  445. deciding to base their systems on it.
  446.  
  447.  
  448. References
  449.  
  450. [1]    John Ousterhout et al, ``The Sprite Network Operating
  451.     System'', IEEE Computer, February 1988.
  452.  
  453. [2]    Brent Welch, ``Naming, State Management, and User-Level
  454.     Extensions in the Sprite Distributed File System'', University
  455.     of California, Berkeley, Technical Report UCB/CSD 90/567,
  456.     February 1990.
  457.  
  458. [3]    Fred Douglis and John Ousterhout, ``Transparent Process
  459.     Migration: Design Alternatives and the Sprite
  460.     Implementation'', Software--Practice & Experience, July 1991.
  461.  
  462. [4]    Mendel Rosenblum and John Ousterhout, ``The Design and
  463.     Implementation of a Log-Structured File System'', Proc.
  464.     Symposium on Operating Systems Principles, October 1991.
  465.  
  466. [5]    M. D. Hill et al, ``Design Decisions in SPUR'', IEEE Computer,
  467.     November 1986.
  468.  
  469. [6]    David Golub et al, ``UNIX as an Application Program'', Proc.
  470.     Summer 1990 USENIX Conference, June 1990.
  471.  
  472. [7]    David L. Black et al, ``Microkernel Operating System
  473.     Architecture and Mach'', Proc. USENIX Microkernel Workshop,
  474.     April 1992.
  475.  
  476. [8]    John Ousterhout, ``Why Aren't Operating Systems Getting Faster
  477.     As Fast as Hardware?'', Proc. Summer 1990 USENIX Conference,
  478.     June 1990.
  479.  
  480. % [9]    Ken Shirriff and John Ousterhout, ``A Trace-driven Analysis of
  481. %     Name and Attribute Caching in a Distributed File System'',
  482. %     Proc. Winter 1992 USENIX Conference, January 1992.
  483.